import "babel-polyfill";
import {MathError} from "../error";
import Integer from "../number/integer";

const {floor} = Math;
const {one, eq, compare, add, multiply, divide, mod, square, pow, shl, shr} = Integer;

const perfect_square_mask = {
    "11": "11011100010",
    "63": "110010010100000010100010010010000000110000010010010000000010000",
    "64": "1100100001000000110000000100000001001000010000000100000001000000",
    "65": "11001000011000101000000001100110000110011000000001010001100001001"
};

export var sqrt = function(n) {
    n = Integer.from(n);
    if (n.sign < 0) {
        throw new MathError(`${n} should be non-negative`);
    }
    var x = n;
    var y = shl(one, (n.bitLength + 1) >>> 1);
    while (compare(x, y) > 0) {
        [x, y] = [y, shr(add(y, divide(n, y)), 1)];
    }
    return x;
};

export var sqrtIfPerfect = function(n) {
    n = Integer.from(n);
    if (n.sign < 0) {
        return;
    } else if (perfect_square_mask[64][n.lastLimb & 0x3f] === "0") {
        return;
    }
    var m = mod(n, 45045);
    if (perfect_square_mask[63][m % 63] === "0"
        || perfect_square_mask[65][m % 65] === "0"
        || perfect_square_mask[11][m % 11] === "0"
    ) {
        return;
    }
    var q = sqrt(n);
    if (eq(square(q), n)) {
        return q;
    }
};

export var isPerfectSquare = function(n) {
    return sqrtIfPerfect(n) !== undefined;
};

export var nthRoot = function(n, root) {
    var m1 = root - 1;
    var x = n;
    var y = shl(one, floor((n.bitLength + m1) / root));
    while (compare(x, y) > 0) {
        [x, y] = [y, divide(add(multiply(y, m1), divide(n, pow(y, m1))), root)];
    }
    return x;
};
